﻿using System;
using System.Data;
using System.Web;
using System.Web.SessionState;

namespace tjb.Utility
{
    /// <summary>
    /// 
    /// </summary>
    public sealed class MySessionModule : IHttpModule
    {

        #region IHttpModule 成员

        public void Dispose()
        {

        }

        public void Init(HttpApplication context)
        {
            context.AcquireRequestState += new EventHandler(context_AcquireRequestState);

            SessionStateModule sessionmodule = context.Modules["Session"] as SessionStateModule;
            if (sessionmodule != null)
            {
                sessionmodule.Start += new EventHandler(sessionmodule_Start);
                sessionmodule.End += new EventHandler(sessionmodule_End);
            }
        }

        void sessionmodule_End(object sender, EventArgs e)
        {
            HttpApplication myApp = sender as HttpApplication;
            OnLineManager.CurrentInstance.RemoveUser(myApp.Context.Application, myApp.Context.Session.SessionID);
        }

        void sessionmodule_Start(object sender, EventArgs e)
        {

        }

        void context_AcquireRequestState(object sender, EventArgs e)
        {
            OnLineManager.Application_AcquireRequestState(sender, e);
        }

        #endregion
    }


    /// <summary>
    ///  在线管理类
    /// <para>by tangjingbo at 2009-5-8 15:50</para>
    /// </summary>
    public sealed class OnLineManager
    {
        /// <summary>
        ///  在线管理的实例
        /// </summary>
        public static OnLineManager CurrentInstance = new OnLineManager();
        private OnLineManager() { }
        private const string App_KEY = "UserOnLine";
        /// <summary>
        ///  登录用户标志
        /// </summary>
        public static string LoginSessionKEY = "UserID";
        private static System.Threading.Timer timer;
        private int _interval = 1000 * 60 * 20;//检查在线用户的间隔时间

        #region 静态方法

        /// <summary>
        /// 获取在线用户列表。不能用于session_end事件，不能用于访问不到HttpContext.Current.Application的上下文中。
        /// <para>by tangjingbo at 2009-5-14 14:44</para>
        /// </summary>
        /// <returns></returns>
        public static DataTable GetCurrentOnline()
        {
            return CurrentInstance.GetOnline(HttpContext.Current.Application);
        }
        /// <summary>
        /// 
        /// <para>by tangjingbo at 2009-5-19 19:13</para>
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        public static void Application_AcquireRequestState(Object sender, EventArgs e)
        {
            CurrentInstance.AcquireRequestState(sender, e);
        }
        /// <summary>
        /// 移除当前用户。不能用于session_end事件，不能用于访问不到HttpContext.Current.Session的上下文中。
        /// <para>by tangjingbo at 2009-5-14 14:31</para>
        /// </summary>
        public static void RemoveCurrentUser()
        {
            if (HttpContext.Current != null && HttpContext.Current.Session != null)
            {
                CurrentInstance.RemoveUser(HttpContext.Current.Application, HttpContext.Current.Session.SessionID);
                HttpContext.Current.Session.Abandon();
            }
        }
        #endregion

        /// <summary>
        /// 获取或设置检查用户时间
        /// <para>by tangjingbo at 2009-5-8 15:58</para>
        /// </summary>
        /// <value></value>
        public int Interval
        {
            get { return _interval; }
            set
            {
                _interval = value;
                newTimer = false;
            }
        }

        private bool newTimer = timer == null;
        private void OnLine_Start(HttpApplication mApp)
        {
            if (newTimer)
            {
                _interval = HttpContext.Current.Session.Timeout * 60 * 500;
                timer = new System.Threading.Timer(new System.Threading.TimerCallback(ScheduledWorkCallback),
                    mApp, 0, Interval);
                DataTable userTable = new DataTable();
                Type dbString = typeof(string);
                Type dbDateTime = typeof(DateTime);
                userTable.Columns.Add("SessionID", dbString);
                userTable.Columns.Add(LoginSessionKEY, dbString);//用户ID
                //     userTable.Columns.Add("UserName", dbString);//用户姓名
                userTable.Columns.Add("FirstRequestTime", dbDateTime);//第一次请求的时间
                userTable.Columns.Add("LastRequestTime", dbDateTime);//最后一次请求的时间
                userTable.Columns.Add("ClientIP", dbString);//
                userTable.Columns.Add("ClientName", dbString);//
                userTable.Columns.Add("ClientAgent", dbString);//
                //userTable.Columns.Add("LastRequestPath");//最后访问的页面

                userTable.PrimaryKey = new DataColumn[] { userTable.Columns[0] };
                userTable.AcceptChanges();

                mApp.Application.Lock();
                mApp.Application.Set(App_KEY, userTable);
                mApp.Application.UnLock();
                newTimer = false;
            }
        }


        /// <summary>
        /// 
        /// <para>by tangjingbo at 2009-5-8 15:50</para>
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        public void AcquireRequestState(Object sender, EventArgs e)
        {
            HttpApplication mApp = sender as HttpApplication;
            OnLine_Start(mApp);

            //如果未登录返回
            if (NoLogin(mApp)) return;

            string SessionID = mApp.Context.Session.SessionID;

            DataTable userTable = mApp.Application[App_KEY] as DataTable;
            DataRow curRow = userTable.Rows.Find(new object[] { SessionID });
            if (curRow != null)
            {
                this.GetDataRowFromHttpApp(mApp, ref curRow);
            }
            else
            {
                DataRow newRow = userTable.NewRow();
                this.GetDataRowFromHttpApp(mApp, ref newRow);
                userTable.Rows.Add(newRow);
            }
            userTable.AcceptChanges();


            mApp.Application.Lock();
            mApp.Application.Set(App_KEY, userTable);
            mApp.Application.UnLock();
            // ApplicationUtility.Set(App_KEY, userTable);     

        }
        /// <summary>
        /// 判断是否登录
        /// <para>by tangjingbo at 2009-5-19 19:02</para>
        /// </summary>
        /// <param name="mApp">The m app.</param>
        /// <returns></returns>
        private bool NoLogin(HttpApplication mApp)
        {
            if (mApp.Context.Session == null || mApp.Context.Session[LoginSessionKEY] == null)
                return true;
            return false;
        }
        private void GetDataRowFromHttpApp(HttpApplication mApp, ref DataRow mRow)
        {
            //如果未登录返回
            if (NoLogin(mApp)) return;
            string userID = mApp.Context.Session[LoginSessionKEY].ToString();
            //   string userName = mApp.Context.Session["UserName"].ToString();
            //string requestPath = mApp.Request.Path;

            if (mRow[LoginSessionKEY].ToString().Length < 1)
            {
                mRow["SessionID"] = mApp.Context.Session.SessionID;
                mRow[LoginSessionKEY] = userID;
                //     mRow["UserName"] = userName;
                mRow["FirstRequestTime"] = System.DateTime.Now;
                mRow["ClientIP"] = mApp.Context.Request.UserHostAddress;
                mRow["ClientName"] = mApp.Context.Request.UserHostName;
                mRow["ClientAgent"] = mApp.Context.Request.UserAgent;
            }

            mRow["LastRequestTime"] = System.DateTime.Now;
            //mRow["LastRequestPath"] = requestPath;

        }

        private void ScheduledWorkCallback(object sender)
        {

            HttpApplication myApp = sender as HttpApplication;
            if (myApp == null)
                myApp = HttpContext.Current.ApplicationInstance;
            if (newTimer)
            {
                timer = new System.Threading.Timer(new System.Threading.TimerCallback(ScheduledWorkCallback),
                  myApp, 0, Interval);
                newTimer = false;
            }
            string filter = "Convert(LastRequestTime,'System.DateTime') < Convert('" + System.DateTime.Now.AddSeconds(-Interval / 1000).ToString() + "','System.DateTime')";
            DataTable userTable = myApp.Application[App_KEY] as DataTable;

            if (userTable == null) return;

            DataRow[] lineOutUsers = userTable.Select(filter);
            for (int i = 0, n = lineOutUsers.Length; i < n; i++)
            {
                DataRow curRow = lineOutUsers[i];
                //保存到数据库 
                curRow.Delete();
            }
            userTable.AcceptChanges();

            myApp.Application.Lock();
            myApp.Application[App_KEY] = userTable;
            myApp.Application.UnLock();

        }



        /// <summary>
        ///  从当前应用程序域中移除sessionid
        /// <para>by tangjingbo at 2009-5-14 14:31</para>
        /// </summary>
        /// <param name="myApplication">My application.</param>
        /// <param name="SessionID">The session ID.</param>
        public void RemoveUser(HttpApplicationState myApplication, String SessionID)
        {
            DataTable userTable = myApplication[App_KEY] as DataTable;
            if (userTable == null) return;
            DataRow curRow = userTable.Rows.Find(new object[] { SessionID });
            if (curRow != null)
            {
                //保存到数据库
                curRow.Delete();

            }
            userTable.AcceptChanges();
            myApplication.Lock();
            myApplication[App_KEY] = userTable;
            myApplication.UnLock();
        }

        /// <summary>
        ///  获取在线用户列表
        /// <para>by tangjingbo at 2009-5-14 14:45</para>
        /// </summary>
        /// <param name="myApplication">My application.</param>
        /// <returns></returns>
        public DataTable GetOnline(HttpApplicationState myApplication)
        {
            return myApplication[App_KEY] as DataTable;
        }


    }
}